package com.frp.lib.handler;

import com.frp.lib.utils.Crypto;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.bouncycastle.crypto.StreamCipher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * Created by hujianjun on 11/29 0029.
 */
public class AESCFBDecoder extends ByteToMessageDecoder {
    private static Logger logger = LoggerFactory.getLogger(AESCFBDecoder.class);

    private String password;
    private String salt = "frp";

    private StreamCipher cipher;

    public AESCFBDecoder(String password) {
        this.password = password;
    }

    public String getSalt() {
        return salt;
    }

    public void setSalt(String salt) {
        this.salt = salt;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
//        logger.info("channel active!");

        super.channelActive(ctx);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        if (null == cipher) {
            if (in.readableBytes() < 16) {
                //iv bytes must 16 len
                return;
            }
            byte[] iv = new byte[16];
            in.readBytes(iv);
            byte[] key = Crypto.encryptPBKDF2(password.toCharArray(), salt.getBytes(), 64, 16 * 8);
            this.cipher = Crypto.buildCipherCFB_BC(key, iv, 128, false);
//            logger.info("key:{}", key);
//            logger.info("iv:{}", iv);
        }
        if (in.readableBytes()<=0)
            return;
//        logger.info("msg:{}", ByteBufUtil.hexDump(in));
        ByteBuf bf = this.decrypt(in);
        out.add(bf);
    }

    private ByteBuf decrypt(ByteBuf in) {
        byte[] bf = new byte[in.readableBytes()];
        in.readBytes(bf);
        cipher.processBytes(bf, 0, bf.length, bf, 0);
        return Unpooled.wrappedBuffer(bf);
    }
}
